//
//  SocketManager.m
//  Server
//
//  Created by jyh on 2018/7/25.
//  Copyright © 2018年 huig. All rights reserved.
//

#import "SocketManager.h"
#import "GCDAsyncSocket.h"
#import "Immessage.pbobjc.h"
#import "MessageCompile.h"
#import "ClientObject.h"
#import "MessageModel.h"
@interface SocketManager()<GCDAsyncSocketDelegate>
@property (nonatomic, strong) NSThread *thread;
/** 心跳定时器 */
//@property (nonatomic, strong) NSTimer *checkTimer;
/** GCDAsyncSocket  */
@property (nonatomic, strong) GCDAsyncSocket *serverSocket;
/** 保存客户端连接数组 */
@property (nonatomic, strong) NSMutableArray *clientSockets;

@end

@implementation SocketManager

static SocketManager *_shareInstance;

+ (instancetype)shareInstance {
    if (!_shareInstance) {
        _shareInstance = [[self alloc] init];
    }
    return _shareInstance;
}

#pragma mark -- 外部接口

/**
 开启连接

 @param post 端口号
 @return 返回结果
 */
- (BOOL)startConnectWithPost:(NSInteger)post {
    [self.thread start];
    NSError *error = nil;
    return [self.serverSocket acceptOnPort:post error:&error];
}

/**
 服务器群发信息给客户端

 @param data 信息data
 */
- (void)sendMessageToClient:(NSData *)data {
    // withTimeout -1 : 无穷大,一直等
    // tag : 消息标记
    for (ClientObject *client in self.clientSockets) {
        [client.clientScocket writeData:data withTimeout:- 1 tag:0];
    }
}

#pragma mark -- GCDAsyncSocketDelegate

/**
 连接上新的客户端socket

 @param sock GCDAsyncSocket
 @param newSocket 客户端socket
 */
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(nonnull GCDAsyncSocket *)newSocket {
    ClientObject *client = [ClientObject new];
    client.clientScocket = newSocket;
    client.timeNew = [NSDate date];
    // 保存客户端的socket
    [self.clientSockets addObject:client];
    
    [self showSystemMessage:[NSString stringWithFormat:@"%@,连接到服务器",client]];
    
    [newSocket readDataWithTimeout:- 1 tag:0];
}

/**
 读取客户端的数据
 
 @param sock 客户端的Socket
 @param data 客户端发送的数据
 @param tag 当前读取的标记
 */
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    
    MessageModel *model = [MessageCompile parsingWithData:data];
    
    // 离开房间
    if (model.type == 3) {
        [self removeCilent:sock];
    }
    
    // 定向信息
    if (model.type == 5) {
        for (ClientObject *socket in self.clientSockets) {
            if ([[self getReceiverName:model.msgData] isEqual:socket.userID]) {
                [socket.clientScocket writeData:data withTimeout:- 1 tag:0];
                break;
            }
        }
    }
    
    // 群聊信息
    for (ClientObject *socket in self.clientSockets) {
        if (![sock isEqual:socket.clientScocket] && model.type != 5) {
            if (model.msgData != nil) {
                // 群聊
                [socket.clientScocket writeData:data withTimeout:- 1 tag:0];
            }
        } else if ([sock isEqual:socket.clientScocket]){
            socket.timeNew = [NSDate date];
            if (model.type == 0) continue;
            if ([self getUserName:model.msgData]) {
                socket.userID = [self getUserName:model.msgData];
            }
            if (model.type == 1){
                [self showSystemMessage:[NSString stringWithFormat:@"IP:%@: %hu",sock.connectedHost,sock.connectedPort]];
            }
        }
    }
    
    [sock readDataWithTimeout:- 1 tag:0];
}


/**
 用户掉线会执行改方法

 @param sock sock
 @param err 错误信息
 */
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
    NSLog(@"用户下线");
    [self removeCilent:sock];
}

#pragma mark -- 内部方法
// 获取接收者名称
- (NSString *)getReceiverName:(id)cls {
    NSString *receiverName;
    if ([cls isKindOfClass:[TextMessage class]]) {
        TextMessage *tm = cls;
        receiverName = tm.msgInfo.receiver;
    } else if ([cls isKindOfClass:[GiftMessage class]]) {
        GiftMessage *gm = cls;
        receiverName = gm.msgInfo.receiver;
    }
    return receiverName;
}

// 获取连接用户名称
- (NSString *)getUserName:(id)cls {
    NSString *userName;
    if ([cls isKindOfClass:[TextMessage class]]) {
        TextMessage *tm = cls;
        userName = tm.user.name;
    } else if ([cls isKindOfClass:[GiftMessage class]]) {
        GiftMessage *gm = cls;
        userName = gm.user.name;
    }
    return userName;
}

// 显示到服务器上的信息
- (void)showSystemMessage:(NSString *)message {
    if ([self.delegate respondsToSelector:@selector(socketManager:message:)]) {
        [self.delegate socketManager:self message:message];
    }
}

/** 定时器  */
- (void)addTimer {
    @autoreleasepool {
        NSLog(@"addTimer = %@",[NSThread currentThread]);
        // 长连接定时器
        [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(checkLongConnect) userInfo:nil repeats:YES];
        // 把定时器添加到当前运行循环,并且调为通用模式
        [[NSRunLoop currentRunLoop] run];
    }
}

// 检测心跳
- (void)checkLongConnect {
    if (self.clientSockets.count == 0) return;
    NSDate *date = [NSDate date];
    NSMutableArray *NewClientSockets = [NSMutableArray array];
    for (ClientObject *client in self.clientSockets) {
        if ([date timeIntervalSinceDate:client.timeNew] > 30) {
            NSString *messageStr = [NSString stringWithFormat:@"断开,时差%f:移除",[date timeIntervalSinceDate:client.timeNew]];
            [self showSystemMessage:messageStr];
            continue;
        }
        [NewClientSockets addObject:client];
    }
    self.clientSockets = NewClientSockets;
}

/**
 从数组删除不在线用户
 */
- (void)removeCilent:(GCDAsyncSocket*)sock {
    NSMutableArray *NewClientSockets = [NSMutableArray array];
    for (ClientObject *socket in self.clientSockets ) {
        if ([socket.clientScocket isEqual:sock]) {
            continue;
        }
        [NewClientSockets addObject:socket];
    }
    self.clientSockets = NewClientSockets;
}


#pragma mark -- 懒加载
// 心跳包线程
- (NSThread *)thread {
    if (!_thread) {
        _thread = [[NSThread alloc] initWithTarget:self selector:@selector(addTimer) object:nil];
    }
    return _thread;
}

// 服务器Socket
- (GCDAsyncSocket *)serverSocket {
    if (!_serverSocket) {
        _serverSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    return _serverSocket;
}

// 保存Socket
- (NSMutableArray *)clientSockets {
    if (!_clientSockets) {
        _clientSockets = [NSMutableArray array];
    }
    return _clientSockets;
}

@end

































